| 1 | //ConnectionServer#init() | 
接收到客户端的Handshake请求,根据SessionContext中是否设置是否启用加密,分2种处理请求:1
2
3
4
5
6
7
8
9//HandshakeHandler.java
public void handle(HandshakeMessage message) {
    if (message.getConnection().getSessionContext().isSecurity()) {
        doSecurity(message);
    } else {
        doInsecurity(message);
    }
}
启用加密的处理:
加解密的交互细节,站内搜索文章:深度进阶-加解密
握手成功,生成session并保存到redis中,用于快速重连;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60private void doSecurity(HandshakeMessage message) {
    byte[] iv = message.iv;//AES密钥向量16位
    byte[] clientKey = message.clientKey;//客户端随机数16位
    byte[] serverKey = CipherBox.I.randomAESKey();//服务端随机数16位
    byte[] sessionKey = CipherBox.I.mixKey(clientKey, serverKey);//会话密钥16位
    //1.校验客户端消息字段
    if (Strings.isNullOrEmpty(message.deviceId)
            || iv.length != CipherBox.I.getAesKeyLength()
            || clientKey.length != CipherBox.I.getAesKeyLength()) {
        ErrorMessage.from(message).setReason("Param invalid").close();
        Logs.CONN.error("handshake failure, message={}, conn={}", message, message.getConnection());
        return;
    }
    //2.重复握手判断
    SessionContext context = message.getConnection().getSessionContext();
    if (message.deviceId.equals(context.deviceId)) {
        ErrorMessage.from(message).setErrorCode(REPEAT_HANDSHAKE).send();
        Logs.CONN.warn("handshake failure, repeat handshake, conn={}", message.getConnection());
        return;
    }
    //3.更换会话密钥RSA=>AES(clientKey)
    context.changeCipher(new AesCipher(clientKey, iv));
    //4.生成可复用session, 用于快速重连
    ReusableSession session = reusableSessionManager.genSession(context);
    //5.计算心跳时间
    int heartbeat = ConfigTools.getHeartbeat(message.minHeartbeat, message.maxHeartbeat);
    //6.响应握手成功消息
    HandshakeOkMessage
            .from(message)
            .setServerKey(serverKey)
            .setHeartbeat(heartbeat)
            .setSessionId(session.sessionId)
            .setExpireTime(session.expireTime)
            .send(f -> {
                        if (f.isSuccess()) {
                            //7.更换会话密钥AES(clientKey)=>AES(sessionKey)
                            context.changeCipher(new AesCipher(sessionKey, iv));
                            //8.保存client信息到当前连接
                            context.setOsName(message.osName)
                                    .setOsVersion(message.osVersion)
                                    .setClientVersion(message.clientVersion)
                                    .setDeviceId(message.deviceId)
                                    .setHeartbeat(heartbeat);
                            //9.保存可复用session到Redis, 用于快速重连
                            reusableSessionManager.cacheSession(session);
                            Logs.CONN.info("handshake success, conn={}", message.getConnection());
                        } else {
                            Logs.CONN.info("handshake failure, conn={}", message.getConnection(), f.cause());
                        }
                    }
            );
}
没有启用加密的处理:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30private void doInsecurity(HandshakeMessage message) {
        //1.校验客户端消息字段
        if (Strings.isNullOrEmpty(message.deviceId)) {
            ErrorMessage.from(message).setReason("Param invalid").close();
            Logs.CONN.error("handshake failure, message={}, conn={}", message, message.getConnection());
            return;
        }
        //2.重复握手判断
        SessionContext context = message.getConnection().getSessionContext();
        if (message.deviceId.equals(context.deviceId)) {
            ErrorMessage.from(message).setErrorCode(REPEAT_HANDSHAKE).send();
            Logs.CONN.warn("handshake failure, repeat handshake, conn={}", message.getConnection());
            return;
        }
        //6.响应握手成功消息
        HandshakeOkMessage.from(message).send();
        //8.保存client信息到当前连接
        context.setOsName(message.osName)
                .setOsVersion(message.osVersion)
                .setClientVersion(message.clientVersion)
                .setDeviceId(message.deviceId)
                .setHeartbeat(Integer.MAX_VALUE);
        Logs.CONN.info("handshake success, conn={}", message.getConnection());
    }
}
session管理1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public final class ReusableSessionManager {
    private final int expiredTime = CC.mp.core.session_expired_time;
    private final CacheManager cacheManager = CacheManagerFactory.create();
    public boolean cacheSession(ReusableSession session) {
        String key = CacheKeys.getSessionKey(session.sessionId);
        cacheManager.set(key, ReusableSession.encode(session.context), expiredTime);
        return true;
    }
    public ReusableSession querySession(String sessionId) {
        String key = CacheKeys.getSessionKey(sessionId);
        String value = cacheManager.get(key, String.class);
        if (Strings.isBlank(value)) return null;
        return ReusableSession.decode(value);
    }
    public ReusableSession genSession(SessionContext context) {
        long now = System.currentTimeMillis();
        ReusableSession session = new ReusableSession();
        session.context = context;
        session.sessionId = MD5Utils.encrypt(context.deviceId + now);
        session.expireTime = now + expiredTime * 1000;
        return session;
    }
}
是否加密的设置代码:1
2
3
4
5public final class ConnectionServer extends NettyTCPServer {
    public ConnectionServer(MPushServer mPushServer) {
        this.channelHandler = new ServerChannelHandler(true, connectionManager, messageDispatcher);
    }
}
| 1 | .Sharable | 
| 1 | public final class NettyConnection implements Connection, ChannelFutureListener { | 
接入服务文章目录: